package com.yuma.tingshu.common.config.redis;

import com.yuma.tingshu.common.constant.RedisConstant;
import com.yuma.tingshu.common.util.LiveRoomContainer;
import com.yuma.tingshu.model.live.SocketMsg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.Topic;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.lang.Nullable;

@Configuration
public class RedisListenerConfig {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 初始化redis监听者容器
     *
     * 当有消息发布到RedisConstant.LIVE_MESSAGE_CHANNEL通道时
     * 监听容器会捕获到这个消息，并触发注册的MessageListener
     * 消息处理逻辑：
     * 通过RedisTemplate的序列化器反序列化消息体（从二进制转为SocketMsg对象）
     * 调用LiveRoomContainer.sendMessage(msg)方法转发消息（通常是转发给 WebSocket 连接的客户端）
     *
     * 关键技术点：
     * 消息反序列化：由于 Redis 存储的是二进制数据，需要通过RedisTemplate的序列化器（与存储时保持一致）将其转回SocketMsg对象
     * 通道监听：通过ChannelTopic指定监听的 Redis 通道，一个容器可以监听多个通道
     * 与 WebSocket 结合：这是典型的 "Redis 发布 - 订阅 + WebSocket" 架构，
     * 用于实现分布式环境下的消息同步（如多服务器节点间的直播间消息同步）
     */
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory factory) {
        // 通过构造方法初始化监听者容器,监听器容器,不是监听器,里面可以放很多的监听器
        RedisMessageListenerContainer listenerContainer = new RedisMessageListenerContainer();
        // 设置连接工厂
        listenerContainer.setConnectionFactory(factory);
        MessageListener messageListener = (Message message, @Nullable byte[] pattern) -> {
            //将message反序列化为SocketMsg byte[]---->Object 反序列化
            RedisSerializer valueSerializer = this.redisTemplate.getValueSerializer();
            SocketMsg socketMsg = (SocketMsg) valueSerializer.deserialize(message.getBody());
            //利用LiveRoomContainer取发消息
            LiveRoomContainer.sendMessage(socketMsg);
            System.out.println("---------------RedisMessageListenerContainer-------------------");
            System.out.println(socketMsg);
        };
        Topic topic = new ChannelTopic(RedisConstant.LIVE_MESSAGE_CHANNEL);
        listenerContainer.addMessageListener(messageListener, topic);
        return listenerContainer;
    }
}
